package br.com.loja.view.swing.form;

import java.awt.Component;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JPanel;
import br.com.loja.model.entity.ObservableEntity;
import br.com.loja.mvp.model.IModel;
import br.com.loja.mvp.presenter.IEntityPresenter;
import br.com.loja.mvp.view.EntityViewHandler;
import br.com.loja.util.reflection.JBean;
import br.com.loja.util.reflection.ReflectionUtil;
import br.com.loja.view.swing.handler.ComponentViewHandlerFactory;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @brief Classe AbstractFormEntity
 * @author David Luiz
 * @date 05/12/2014
 */
public class AbstractFormEntity<T extends ObservableEntity & IModel<T>> extends JPanel implements IFormEntity<T> {

    protected final IEntityPresenter<T> presenter;
    protected final Map<String, Component> attributeComponents;

    public AbstractFormEntity(IEntityPresenter<T> presenter) {
        super();
        this.presenter = presenter;
        this.attributeComponents = new HashMap<>(16);

    }

    @Override
    public void clearForm() {
        setModelToForm(null);
    }

    @Override
    public void disableForm(boolean op) {
        setEnabledEntityAtribute(op);
    }

    @Override
    public void setModel(T model) {
        setModelToForm(model);
    }

    @Override
    public T getModel(T model) {
        return getModelFromForm(model);
    }

    @Override
    public void grabFocus() {
        setGrabFocus();
    }

    private void setEnabledEntityAtribute(boolean op) {
        List<Field> attributes = ReflectionUtil.getAllFields(presenter.getClassModel());

        for (Field attribute : attributes) {

            JComponent component = (JComponent) attributeComponents.get(attribute.getName());

            if (component == null) {
                continue;
            }

            component.setEnabled(op);

        }
    }

    private void setGrabFocus() throws SecurityException {
        List<Field> attributes = ReflectionUtil.getAllFields(presenter.getClassModel());

        for (Field attribute : attributes) {

            JComponent component = (JComponent) attributeComponents.get(attribute.getName());

            if (component == null) {
                continue;
            }

            component.grabFocus();
            break;
        }

    }

    private void setModelToForm(T model) {
        List<Field> attributes = ReflectionUtil.getAllFields(presenter.getClassModel());

        for (Field attribute : attributes) {

            Component component = attributeComponents.get(attribute.getName());

            if (component == null) {
                continue;
            }

            if (model == null) {
                getEntityViewHandler(component, attribute.getName()).setValue(null);
                continue;
            }

            JBean bean = new JBean(model, attribute.getName());
            Object value = bean.getValue();

            getEntityViewHandler(component, attribute.getName()).setValue(value);

        }

    }

    private T getModelFromForm(T model) {
        List<Field> attributes = ReflectionUtil.getAllFields(presenter.getClassModel());

        for (Field attribute : attributes) {

            Component component = attributeComponents.get(attribute.getName());

            if (component == null) {
                continue;
            }

            Object value = getEntityViewHandler(component, attribute.getName()).getValue();

            JBean bean = new JBean(model, attribute.getName());
            bean.setValue(value);

        }

        return model;

    }

    private EntityViewHandler getEntityViewHandler(Component component, String attribute) {
        String methodGetAttribute = "get" + String.valueOf(attribute.charAt(0)).toUpperCase() + attribute.substring(1);

        Method method = ReflectionUtil.getMethodByName(presenter.getClassModel(), methodGetAttribute);

        if (method == null) {
            throw new NoSuchFieldError("attribute not found in model's class: " + attribute);
        }

        Class<?> type = method.getReturnType();

        return ComponentViewHandlerFactory.getViewHandler(component, type);

    }

}
